package com.glc.hms.common.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * 关于日期类使用原则:
 * <p>
 * 所有的日期运算均使用java.util.Date类进行比较和增减运算，禁止直接使用字符串！
 * 需要字符串时，先转换为日期类型运算完毕再转换为字符串。避免产生太多的静态方法！
 */
public class DateTimeUtils extends DateUtils {

    // 定义的时间转换格式，可以根据自己需要的格式进行拓展
    private static final String DATE_PATTERN = "yyyy-MM-dd";
    private static final String COMPACT_DATE_PATTERN = "yyyyMMdd";
    private static final String COMPACT_TIME_PATTERN = "HHmmss";
    private static final String MM_TIME_PATTERN = "HH:mm";
    private static final String MM_TIME_PATTERN_CHINA = "HH分mm秒";
    private static final String C_MM_TIME_PATTERN = "ahh:mm";   //下午01:40
    private static final String TIME_PATTERN = "HH:mm:ss";
    private static final String MIL_PATTERN = "HH:mm:ss:SSS";
    private static final String TIME_PATTERN_WEEK = "yyyy-MM-dd E";
    private static final String DATE_PATTERN_CN = "yyyy年MM月dd日";
    private static final String DATE_TIME_ALL = "yyyy.MM.dd HH:mm:ss";
    private static final String DATE_DAY = "dd日";
    /* ------------------------------  类型转换方法 --------------------------- */

    /**
     * Date->String 格式：自定义格式
     */
    public static final String convertDateToString(Date aDate, String pattern) {
        return aDate == null ? null : (new SimpleDateFormat(pattern)).format(aDate);
    }

    /**
     * Date->String 格式：yyyy-MM-dd E 周末时间
     */
    public static final String convertDateToWeekString(Date aDate) {
        return aDate == null ? null : (new SimpleDateFormat(TIME_PATTERN_WEEK)).format(aDate);
    }

    /**
     * Date->String 格式：yyyy-MM-dd
     */
    public static final String convertDateToString(Date aDate) {
        return aDate == null ? null : (new SimpleDateFormat(DATE_PATTERN)).format(aDate);
    }

    /**
     * String->Date 格式：yyyy-MM-dd
     */
    public static Date convertStringToDate(String strDate) throws ParseException {
        return StringUtils.isBlank(strDate) ? null : (new SimpleDateFormat(DATE_PATTERN)).parse(strDate);
    }

    /**
     * String->java.sql.Date 格式：yyyy-MM-dd
     */
    public static java.sql.Date convertStringToSqlDate(String strDate) throws ParseException {
        return new java.sql.Date((new SimpleDateFormat(DATE_PATTERN)).parse(strDate).getTime());
    }

    /**
     * Date->String 格式：yyyy年MM月dd日
     */
    public static final String convertDateToCnString(Date aDate) {
        return aDate == null ? null : (new SimpleDateFormat(DATE_PATTERN_CN)).format(aDate);
    }

    /**
     * String->Date 格式：yyyy年MM月dd日
     */
    public static final Date convertCnStringToDate(String cnString) throws ParseException {
        return StringUtils.isBlank(cnString) ? null : (new SimpleDateFormat(DATE_PATTERN_CN)).parse(cnString);
    }

    /**
     * Date->String 格式：yyyy.MM.dd HH:mm:ss
     */
    public static final String convertDateToAllString(Date aDate) {
        return aDate == null ? null : (new SimpleDateFormat(DATE_TIME_ALL)).format(aDate);
    }

    /**
     * Date->String 格式：yyyyMMdd
     */
    public static final String convertDateToCompactString(Date aDate) {
        return aDate == null ? null : (new SimpleDateFormat(COMPACT_DATE_PATTERN)).format(aDate);
    }

    /**
     * String->Date 格式：yyyyMMdd
     */
    public static Date convertCompactStringToDate(String strDate) throws ParseException {
        return (new SimpleDateFormat(COMPACT_DATE_PATTERN)).parse(strDate);
    }

    /**
     * Date->String 格式：yyyyMMdd HHmmss
     */
    public static final String convertTimeToCompactString(Date aDate) {
        return aDate == null ? null : (new SimpleDateFormat(COMPACT_DATE_PATTERN + COMPACT_TIME_PATTERN)).format(aDate);
    }

    /**
     * String->Date 格式：yyyyMMdd HHmmss
     */
    public static Date convertCompactStringToTime(String strDate) throws ParseException {
        return (new SimpleDateFormat(COMPACT_DATE_PATTERN + COMPACT_TIME_PATTERN)).parse(strDate);
    }

    /**
     * Date->String 格式：HH:mm
     */
    public static final String convertMmTimeToString(Date aTime) {
        return aTime == null ? null : (new SimpleDateFormat(MM_TIME_PATTERN)).format(aTime);
    }

    /**
     * String->Date 格式：HH:mm
     */
    public static Date convertStringToMmTime(String strMmTime) throws ParseException {
        return StringUtils.isBlank(strMmTime) ? null : new Date((new SimpleDateFormat(MM_TIME_PATTERN)).parse(strMmTime).getTime());
    }

    /**
     * Date->String 格式：HH分mm秒
     */
    public static final String convertMmTimeToChinaString(Date aTime) {
        return aTime == null ? null : (new SimpleDateFormat(MM_TIME_PATTERN_CHINA)).format(aTime);
    }

    /**
     * Date->String 格式：ahh:mm 下午01:40
     */
    public static final String convertCMmTimeToString(Date aTime) {
        return aTime == null ? null : (new SimpleDateFormat(C_MM_TIME_PATTERN)).format(aTime);
    }


    public static Date convertStringToCMmTime(String strMmTime) throws ParseException {
        return new Date((new SimpleDateFormat(DATE_PATTERN + " " + C_MM_TIME_PATTERN)).parse(strMmTime).getTime());
    }

    public static final String convertDateTimeToString(Date aDateTime) {
        return aDateTime == null ? null : (new SimpleDateFormat(DATE_PATTERN + " " + TIME_PATTERN)).format(aDateTime);
    }

    public static final String convertDateTimeToMilString(Date aDateTime) {
        return aDateTime == null ? null : (new SimpleDateFormat(DATE_PATTERN + " " + MIL_PATTERN)).format(aDateTime);
    }

    public static final String convertDateTimeToMmString(Date aDateTime) {
        return aDateTime == null ? null : (new SimpleDateFormat(DATE_PATTERN + " " + MM_TIME_PATTERN)).format(aDateTime);
    }

    public static final Date convertMmStringToDateTime(String strMmDateTime) throws ParseException {
        return StringUtils.isBlank(strMmDateTime) ? null : new Date((new SimpleDateFormat(DATE_PATTERN + " " + MM_TIME_PATTERN)).parse(strMmDateTime).getTime());
    }

    public static Date convertStringToDateTime(String strDateTime) throws ParseException {
        return StringUtils.isBlank(strDateTime) ? null : new Date((new SimpleDateFormat(DATE_PATTERN + " " + TIME_PATTERN)).parse(strDateTime).getTime());
    }

    public static Date convertStringToDateTime(String datePattern, String strDateTime) {
        try {
            return new Date((new SimpleDateFormat(datePattern)).parse(strDateTime).getTime());
        } catch (ParseException e) {
            throw new IllegalArgumentException(e);
        }
    }

    /* -----------------------------  以下是日期运算方法 --------------------------- */

    /**
     * 获取月最后时间
     */
    public static Date getMonthEndTime(Calendar calendar) {
        Calendar tmpCalendar = (Calendar) calendar.clone();
        tmpCalendar.set(Calendar.DAY_OF_MONTH, 1);
        tmpCalendar.set(Calendar.HOUR_OF_DAY, 0);
        tmpCalendar.set(Calendar.MINUTE, 0);
        tmpCalendar.set(Calendar.SECOND, 0);
        tmpCalendar.set(Calendar.MILLISECOND, 0);

        tmpCalendar.add(Calendar.MONTH, 1);
        tmpCalendar.add(Calendar.MILLISECOND, -1);
        //毫秒统一设置为0，避免因为毫秒导致进位
        tmpCalendar.set(Calendar.MILLISECOND, 0);
        return tmpCalendar.getTime();
    }

    public static Date getMonthEndTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return getMonthEndTime(calendar);
    }

    public static Date getMonthEndTime(int year, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1);
        return getMonthEndTime(calendar);
    }

    /**
     * 获取月开始时间
     */
    public static Date getMonthStartTime(Calendar calendar) {
        Calendar tmpCalendar = (Calendar) calendar.clone();
        tmpCalendar.set(Calendar.DAY_OF_MONTH, 1);
        tmpCalendar.set(Calendar.HOUR_OF_DAY, 0);
        tmpCalendar.set(Calendar.MINUTE, 0);
        tmpCalendar.set(Calendar.SECOND, 0);
        tmpCalendar.set(Calendar.MILLISECOND, 0);
        return tmpCalendar.getTime();
    }

    public static Date getMonthStartTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return getMonthStartTime(calendar);
    }

    public static Date getMonthStartTime(int year, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1);
        return getMonthStartTime(calendar);
    }

    /**
     * 获取天的最后时间
     */
    public static Date getDayEndTime(Calendar calendar) {
        Calendar tmpCalendar = (Calendar) calendar.clone();
        tmpCalendar.set(Calendar.HOUR_OF_DAY, 0);
        tmpCalendar.set(Calendar.MINUTE, 0);
        tmpCalendar.set(Calendar.SECOND, 0);
        tmpCalendar.set(Calendar.MILLISECOND, 0);

        tmpCalendar.add(Calendar.DATE, 1);
        tmpCalendar.add(Calendar.MILLISECOND, -1);
        //毫秒统一设置为0，避免因为毫秒导致进位
        tmpCalendar.set(Calendar.MILLISECOND, 0);
        return tmpCalendar.getTime();
    }

    public static Date getDayEndTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return getDayEndTime(calendar);
    }

    public static Date getDayEndTime(int year, int month, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1);
        calendar.set(Calendar.DAY_OF_MONTH, day);
        return getDayEndTime(calendar);
    }

    public static Date getDayEndTime(String date) {
        if (StringUtils.isBlank(date)) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(DateTimeUtils.convertStringToDateTime(DATE_PATTERN, date));
        return getDayEndTime(calendar);
    }

    /**
     * 获取天的开始时间
     */
    public static Date getDayStartTime(Calendar calendar) {
        Calendar tmpCalendar = (Calendar) calendar.clone();
        tmpCalendar.set(Calendar.HOUR_OF_DAY, 0);
        tmpCalendar.set(Calendar.MINUTE, 0);
        tmpCalendar.set(Calendar.SECOND, 0);
        tmpCalendar.set(Calendar.MILLISECOND, 0);
        return tmpCalendar.getTime();
    }

    public static Date getDayStartTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return getDayStartTime(calendar);
    }

    public static Date getDayStartTime(int year, int month, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1);
        calendar.set(Calendar.DAY_OF_MONTH, day);
        return getDayStartTime(calendar);
    }

    public static Date getDayStartTime(String date) {
        if (StringUtils.isBlank(date)) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(DateTimeUtils.convertStringToDateTime(DATE_PATTERN, date));
        return getDayStartTime(calendar);
    }

    /**
     * 获取周的开始时间
     */
    public static Date getWeekStartTime(Calendar calendar) {
        Calendar tmpCalendar = (Calendar) calendar.clone();
        tmpCalendar.set(Calendar.HOUR_OF_DAY, 0);
        tmpCalendar.set(Calendar.MINUTE, 0);
        tmpCalendar.set(Calendar.SECOND, 0);
        tmpCalendar.set(Calendar.MILLISECOND, 0);
        tmpCalendar.setFirstDayOfWeek(Calendar.MONDAY);
        tmpCalendar.set(Calendar.DAY_OF_WEEK, tmpCalendar.getFirstDayOfWeek());
        return tmpCalendar.getTime();
    }

    public static Date getWeekStartTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return getWeekStartTime(calendar);
    }

    /**
     * 获取周的结束时间
     */
    public static Date getWeekEndTime(Calendar calendar) {
        Calendar tmpCalendar = (Calendar) calendar.clone();
        tmpCalendar.set(Calendar.HOUR_OF_DAY, 0);
        tmpCalendar.set(Calendar.MINUTE, 0);
        tmpCalendar.set(Calendar.SECOND, 0);
        tmpCalendar.set(Calendar.MILLISECOND, 0);
        tmpCalendar.setFirstDayOfWeek(Calendar.MONDAY);
        tmpCalendar.set(Calendar.DAY_OF_WEEK, tmpCalendar.getFirstDayOfWeek());
        tmpCalendar.add(Calendar.DATE, 7);
        tmpCalendar.set(Calendar.MILLISECOND, -1);
        //毫秒统一设置为0，避免因为毫秒导致进位
        tmpCalendar.set(Calendar.MILLISECOND, 0);
        return tmpCalendar.getTime();
    }

    public static Date getWeekEndTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return getWeekEndTime(calendar);
    }

    /**
     * 获取传入时间处于一周中的第几天 格式：星期*
     * @param date
     * @return
     */
    public static String getDayOfWeekStr(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        String str = "";
        switch (calendar.get(Calendar.DAY_OF_WEEK)) {
            case 1:
                str = "星期日";
                break;
            case 2:
                str = "星期一";
                break;
            case 3:
                str = "星期二";
                break;
            case 4:
                str = "星期三";
                break;
            case 5:
                str = "星期四";
                break;
            case 6:
                str = "星期五";
                break;
            case 7:
                str = "星期六";
                break;
            default:
                break;
        }
        return str;
    }

    /**
     * 获取传入时间处于一周中的第几天 格式：周*
     * @param date
     * @return
     */
    public static String getDayOfWeekStrExt(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        String str = "";
        switch (calendar.get(Calendar.DAY_OF_WEEK)) {
            case 1:
                str = "周日";
                break;
            case 2:
                str = "周一";
                break;
            case 3:
                str = "周二";
                break;
            case 4:
                str = "周三";
                break;
            case 5:
                str = "周四";
                break;
            case 6:
                str = "周五";
                break;
            case 7:
                str = "周六";
                break;
            default:
                break;
        }
        return str;
    }

    /**
     * 获取当前时间Calendar所表示的时间中的 时 时间单位的值
     * @param date
     * @return
     */
    public static int getHourOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.HOUR_OF_DAY);
    }

    /**
     * 获取当前时间Calendar所表示的时间中的 分钟 时间单位的值
     * @param date
     * @return
     */
    public static int getMinuteOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.MINUTE);
    }

    /**
     * 获取当前时间Calendar所表示的时间中的 年 时间单位的值
     * @param date
     * @return
     */
    public static int getYearOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.YEAR);
    }


    //---------------------------------------------------------

    public static Date getCurentWeekStartTime() {
        return getWeekStartTime(new Date());
    }

    public static Date getCurentWeekEndTime() {
        return getWeekEndTime(new Date());
    }

    public static Date getCurentMonthStartTime() {
        return getMonthStartTime(new Date());
    }

    public static Date getCurentMonthEndTime() {
        return getMonthEndTime(new Date());
    }


    public static String getTimeString(Long millisecond) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(millisecond);
        return (new SimpleDateFormat(DATE_PATTERN + " " + TIME_PATTERN)).format(calendar.getTime());
    }

    /**
     * 2018-1-1 00:00:00 - 2017-12-31 11:59:59 = 1
     * date2比date1大的天数
     */
    public static int betweenDays(Date date1, Date date2) {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);
        int day1 = cal1.get(Calendar.DAY_OF_YEAR);
        int day2 = cal2.get(Calendar.DAY_OF_YEAR);
        int year1 = cal1.get(Calendar.YEAR);
        int year2 = cal2.get(Calendar.YEAR);
        if (year1 != year2) {
            int timeDistance = 0;
            for (int i = year1; i < year2; i++) {
                if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) {// 闰年
                    timeDistance += 366;
                } else {// 不是闰年
                    timeDistance += 365;
                }
            }
            return timeDistance + (day2 - day1);
        } else {
            return day2 - day1;
        }
    }


    /**
     * 计算两个日期相差的月份数
     *
     * @param date1 日期1
     * @param date2 日期2
     * @return 相差的月份数
     */
    public static Integer betweenMonths(Date date1, Date date2) {

        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        c1.setTime(date1);
        c2.setTime(date2);

        int year = c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR);

        //开始日期若小月结束日期
        if (year < 0) {
            year = -year;
            return year * 12 + c1.get(Calendar.MONTH) - c2.get(Calendar.MONTH);
        }

        return year * 12 + c2.get(Calendar.MONTH) - c1.get(Calendar.MONTH);
    }

    /**
     * 增减天数(+1:明天.-1:昨天)
     */
    public static Date addDay(Date date, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, day);
        return calendar.getTime();
    }

    /**
     * 添加/减少分钟
     */
    public static Date addAndSubMin(Date date, int min) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MINUTE, min);
        return calendar.getTime();
    }

    /**
     * 计算两个日期相差年数
     */
    public static Integer betweenYears(Date startDate, Date endDate) {
        Calendar startCalendar = Calendar.getInstance();
        Calendar endCalendar = Calendar.getInstance();
        startCalendar.setTime(startDate);
        endCalendar.setTime(endDate);
        return endCalendar.get(Calendar.YEAR) - startCalendar.get(Calendar.YEAR);
    }

    /**
     * 通过生日计算年龄
     */
    public static Integer calculateAge(Date birthday) {
        Integer age = birthday == null ? 0 : DateTimeUtils.betweenYears(birthday, new Date());
        return age == 0 ? 1 : age;
    }


    /**
     * 两个日期之间相差秒数
     * 结束- 开始
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static int getDateDifference(Date startDate, Date endDate) {
        return getMillisecondDifference(startDate, endDate) / 1000;
    }

    /**
     * 两个日期之间相差毫秒数
     * 结束- 开始
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static int getMillisecondDifference(Date startDate, Date endDate) {
        long a = startDate.getTime();
        long b = endDate.getTime();
        return (int) (b - a);
    }

    /**
     * 把两个毫秒数差值传进来就可以看见相差多久
     *
     * @param mss
     * @return
     */
    public static String formatDuring(long mss) {
        long days = mss / (1000 * 60 * 60 * 24);
        long hours = (mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60);
        long minutes = (mss % (1000 * 60 * 60)) / (1000 * 60);
        long seconds = (mss % (1000 * 60)) / 1000;
        return (days > 0 ? (days + "天") : "") + (hours > 0 ? (hours + "时") : "") + (minutes > 0 ? (minutes + "分") : "")
                + (seconds > 0 ? seconds + "秒 " : "");
    }

    /**
     * 获取当年年份
     *
     * @return
     */
    public static String getCurrentYear() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
        Date date = new Date();
        return sdf.format(date);
    }

    /**
     * @param date 要判断是否在当天24h内的时间
     * @return 是否为当天24h内
     * boolean
     * @Description
     */
    public static boolean isToday(Date date) {
        Calendar c1 = Calendar.getInstance();
        c1.setTime(date);
        int year1 = c1.get(Calendar.YEAR);
        int month1 = c1.get(Calendar.MONTH) + 1;
        int day1 = c1.get(Calendar.DAY_OF_MONTH);
        Calendar c2 = Calendar.getInstance();
        c2.setTime(new Date());
        int year2 = c2.get(Calendar.YEAR);
        int month2 = c2.get(Calendar.MONTH) + 1;
        int day2 = c2.get(Calendar.DAY_OF_MONTH);
        if (year1 == year2 && month1 == month2 && day1 == day2) {
            return true;
        }
        return false;
    }

    /**
     * 获取指定月份第一天Date
     *
     * @param dateStr yyyy-MM
     * @return Date类型时间
     */
    public static Date getFirstDayByMonth(String dateStr) throws Exception {
        dateStr = dateStr + "-01";
        return convertStringToDate(dateStr);
    }

    /**
     * 获取指定月份下个月第一天Date
     *
     * @param dateStr
     * @return
     */
    public static Date getNextFirstDayByMonth(String dateStr) throws Exception {
        Date date = getFirstDayByMonth(dateStr);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, 1);
        return calendar.getTime();
    }

    /**
     * 得到当天字符串 格式（dd）
     */
    public static final String getDayString(Date aDate) {
        return aDate == null ? null : (new SimpleDateFormat(DATE_DAY)).format(aDate);
    }
}
